#include "../source/message.hpp"
#include "../source/net.hpp"
#include <future>
#include <mutex>

namespace ns_Req
{
    class Requestor
    {
    public:
        using ptr = std::shared_ptr<Requestor>;
        using Requestcb = std::function<void(const BaseMessage::ptr& msg)>;
        using AsyncResponse = std::future<BaseMessage::ptr>;
        struct RequestDescribe
        {
            using ptr = std::shared_ptr<RequestDescribe>;
            BaseMessage::ptr _req;
            Requestcb _cb;
            std::promise<BaseMessage::ptr> _response;
            Rtype _rtype;
        };

        void OnRequest(const BaseConnection::ptr& conn,const BaseMessage::ptr& msg)
        {
            std::string rid = msg->Getid();
            auto rdp = GetDescribe(rid);
            if(rdp.get() == nullptr)
            {
                LOG(ERROR,"获取req描述对象失败!!!");
                return;
            }
            if(rdp->_rtype == ns_fields::Rtype::REQ_ASYNC)
                return rdp->_response.set_value(msg); //异步操作完成后，就有结果
            else if(rdp->_rtype == Rtype::REQ_CALLBACK)
                return rdp->_cb(msg);
            else
                LOG(ERROR,"未知错误!!!");
        }
        //客户端自己设置为异步响应类型
        bool Send(const BaseConnection::ptr& conn,const BaseMessage::ptr& req,AsyncResponse& async)
        {
            auto rd = newDescribe(req,Rtype::REQ_ASYNC);
            if(rd.get() == nullptr)
            {
                LOG(ERROR,"构建req描述对象失败!!!");
                return false;
            }
            async = rd->_response.get_future();
            return true;
        }
        //客户端自己设置为同步响应类型
        bool Send(const BaseConnection::ptr& conn,const BaseMessage::ptr& req,BaseMessage::ptr& rsp)
        {
            AsyncResponse async;
            bool ret = Send(conn,req,async);
            if(ret == false)
            {
                return false;
            }
            rsp = async.get();
            return true;
        }

        //疑问：这里是客户端自己设置回调进行处理，那Rtype已经是回调了，不就和newDescribe里的判断回调重复了？
        bool Send(const BaseConnection::ptr& conn,const BaseMessage::ptr& req,Requestcb cb)
        {
            auto rd = newDescribe(req,Rtype::REQ_CALLBACK);
            if(rd.get() == nullptr)
            {
                LOG(ERROR,"构建req描述对象失败!!!");
                return false;
            }
            rd->_cb = cb;
            return true;
        }
        
    private:
        RequestDescribe::ptr newDescribe(const BaseMessage::ptr& req,Rtype rtype,const Requestcb& cb = Requestcb())
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto rd = std::make_shared<RequestDescribe>();
            rd->_req = req;
            rd->_rtype = rtype;
            if (rtype == Rtype::REQ_CALLBACK && cb) 
                rd->_cb = cb;
            _hashreq.insert(std::make_pair(req->Getid(),rd));
            return rd;
        }
        RequestDescribe::ptr GetDescribe(std::string id)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _hashreq.find(id);
            if(it == _hashreq.end())
            {
                return RequestDescribe::ptr();
            }
            return it->second;
        }
        void RemoveDescribe(std::string id)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _hashreq.erase(id);
        }
        std::mutex _mutex;
        std::unordered_map<std::string,RequestDescribe::ptr> _hashreq;
    };
};